<?php
namespace Quality\Start;

use \Symfony\Component\HttpKernel\HttpKernelInterface;
use \Symfony\Component\HttpFoundation\Request;
use \Symfony\Component\HttpFoundation\Response;
use \Symfony\Component\HttpKernel\Debug\ErrorHandler;
use \Symfony\Component\HttpKernel\Debug\ExceptionHandler;
use \Symfony\Component\HttpKernel\HttpKernel;
use \Symfony\Component\DependencyInjection\ContainerInterface;
use \Symfony\Component\DependencyInjection\Container;
use \Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager;
use \Symfony\Component\Security\Core\SecurityContext;

/**
 * Aplicação base para todas aplicações
 */
class Application
{
    /**
     * @var HttpKernel
     */
    protected $routeManager;

    /**
     * @var ErrorHandler
     */
    protected $errorHandler;

    /**
     * @var ContainerInterface
     */
    private $dependencyContainer;

    /**
     * @var Request
     */
    protected $request;

    /**
     * @var Response
     */
    protected $response;

    /**
     * @param \Symfony\Component\HttpKernel\Debug\ErrorHandler $errorHandler
     * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
     *
     * @throws \InvalidArgumentException
     */
    public function __construct(ErrorHandler $errorHandler, ContainerInterface $container)
    {
        if (!($container instanceof \Symfony\Component\DependencyInjection\Container)) {
            throw new \InvalidArgumentException(
                'The container must be a \Symfony\Component\DependencyInjection\Container instance. Instance of '
                    . get_class($container) . 'given.');
        }

        $this->dependencyContainer = $container;
        $this->routeManager = $this->dependencyContainer->get('kernel');
        $this->errorHandler = $errorHandler;
    }

    /**
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
     */
    public function getDependencyContainer()
    {
        return $this->dependencyContainer;
    }

    /**
     * @return HttpKernel
     */
    public function getRouteManager()
    {
        return $this->routeManager;
    }

    /**
     * @return Response
     */
    public function getResponse()
    {
        if ($this->response === null) {
            $this->response = new Response();
        }

        return $this->response;
    }

    /**
     * @return Request
     */
    public function getRequest()
    {
        if ($this->request === null) {
            $this->request = Request::createFromGlobals();
        }

        return $this->request;
    }

    /**
     * Executes the application
     */
    public function run()
    {
        try {
            $this->getRequest()->attributes->add(array('application' => $this));
            ob_start();
            $this->response = $this->getRouteManager()->handle($this->getRequest(), HttpKernelInterface::SUB_REQUEST);
            ob_end_clean();
            $this->sendResponse();
        } catch (\ErrorException $error) {
            $this->errorHandler = ErrorHandler::register()->handle(
                $error->getCode(),
                $error->getMessage(),
                $error->getFile(),
                $error->getLine(),
                $error->getTrace()
            );
        }
    }

    /**
     * Sends the response to the browser
     */
    protected function sendResponse()
    {
        $response = $this->getResponse();
        $response->prepare($this->getRequest());
        $response->send();
    }
}
